//******************************************************************************************************
// Copyright 2008 Amazon Technologies, Inc.  
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in 
// compliance with the License. 
//
// You may obtain a copy of the License at:http://aws.amazon.com/apache2.0  This file is distributed on 
// an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
//
// See the License for the specific language governing permissions and limitations under the License. 
//******************************************************************************************************
using System;
using System.Collections;
using System.Text;
using System.Diagnostics;
using System.Net;
using System.Xml;
using System.Threading;
//
// References for SQS operations...
//
using Amazon.SQS;
using Amazon.SQS.Mock;
using Amazon.SQS.Model;
namespace SQS_Client
{
    public class Client
    {
        private static AmazonSQSClient _sqsClient   = null;
        private static Uri             _sqsURI      = null;
    
        public static Uri Uri
        {
            get { return _sqsURI;}
            set { _sqsURI = value;}
        }

        public static void SetConnectionLimit(int limit)
        {
            ServicePoint sp;
            try
            {
                sp                 = ServicePointManager.FindServicePoint(_sqsURI);
                sp.ConnectionLimit = limit;
            }
            catch { }
        }
    
        public static void Startup(string accessKey, string secretKey)
        {
            AmazonSQSConfig config = new AmazonSQSConfig();
            config.UserAgent  = "SQS Windows Requestor-Worker Component v1.0";
            _sqsClient         = new AmazonSQSClient(accessKey, secretKey, config);
            _sqsURI            = new Uri(config.ServiceURL);
        }

        public static void Startup(string access_key, string secret_key, string endpoint)
        {
            AmazonSQSConfig config = new AmazonSQSConfig();
            
            config.ServiceURL = endpoint;
            _sqsClient         = new AmazonSQSClient(access_key, secret_key, config);
            _sqsURI            = new Uri(endpoint);
        }

        /// <summary>
        /// Parse any possible errors
        /// </summary>
        /// <param name="sqsException"></param>
        /// <returns></returns>
        private static string ProcessSQSError(AmazonSQSException sqsException)
        {
            string rs = null;
            switch(sqsException.ErrorCode)
            {
                case "InvalidClientTokenId":
                case "SignatureDoesNotMatch":
                    rs = "Invalid AWS credentials - " + sqsException.ErrorCode;
                    break;
                case "OptInRequired":
                    rs = "Your AWS account does not have SQS access - " + sqsException.ErrorCode;
                    break;
                default:    // General SQS Error, retry
                    rs = "General error - " + sqsException.ErrorCode;
                    break;
            }
            return rs;
        }

        /// <summary>
        /// Create a queue
        /// </summary>
        /// <param name="queueName"></param>
        /// <returns></returns>
        public static string CreateQueue(string queueName)
        {
            CreateQueueResponse     response     = null;
            CreateQueue             request;
            string                  errorMessage = null;
        
            request             = new CreateQueue();
            request.QueueName   = queueName;
            
            //
            // Make request - retry if we get a 5xx error
            //
            try
            {
                response = _sqsClient.CreateQueue(request);
            }
            catch (AmazonSQSException sqsException)
            {
                //
                // Oops - caught SQS error.  Process message...
                //
                errorMessage = ProcessSQSError(sqsException);
            }
            catch (Exception ex)
            {
                //
                // Oops - caught an error.
                //
                errorMessage = "Generic Error: " + ex.Message;
            }

            //
            // Generate a exception for this error - allow caller to have consistent handling
            //
            if (errorMessage != null)
            {
                throw new Exception("CreateQueue Error - " + errorMessage);
            }
        
            return response.CreateQueueResult.QueueUrl;
        }
        
        /// <summary>
        /// Call ListQueues for queues that are owned by the specified X.509 Certificate... 
        /// </summary>
        /// <returns></returns>
        public static string[] ListQueues()
        {
            ListQueues              listQueues;
            ListQueuesResponse      response        = null;
            string                  errorMessage    = null;
            string[]                results         = null;
        
            listQueues = new ListQueues();
            
            //
            // Make request - retry if we get a 5xx error
            //
            try
            {
                response = _sqsClient.ListQueues(listQueues);
            }
            catch (AmazonSQSException sqsException)
            {
                //
                // Oops - caught SQS error.  Process message...
                //
                errorMessage = ProcessSQSError(sqsException);
            }
            catch (Exception ex)
            {
                //
                // Oops - caught an error.
                //
                errorMessage = "Generic Error: " + ex.Message;
            }

            //
            // Generate a exception for this error - allow caller to have consistent handling
            //
            if (errorMessage != null)
            {
                throw new Exception("ListQueues Error - " + errorMessage);
            }
        
            results = new string[response.ListQueuesResult.QueueUrl.Count];
            response.ListQueuesResult.QueueUrl.CopyTo(results);
        
            return results;
        }
        
        /// <summary>
        /// Delete a queue
        /// </summary>
        /// <param name="queue"></param>
        /// <returns></returns>
        public static string DeleteQueue(string queue)
        {
            DeleteQueue             deleteQueue;
            DeleteQueueResponse     response        = null;
            string                  errorMessage    = null;
        
            deleteQueue             = new DeleteQueue();
            deleteQueue.QueueName   = queue;
        
            //
            // Make request - retry if we get a 5xx error
            //
            try
            {
                response = _sqsClient.DeleteQueue(deleteQueue);
            }
            catch (AmazonSQSException sqsException)
            {
                //
                // Oops - caught SQS error.  Process message...
                //
                errorMessage = ProcessSQSError(sqsException);
            }
            catch (Exception ex)
            {
                //
                // Oops - caught an error.
                //
                errorMessage = "Generic Error: " + ex.Message;
            }
        
            //
            // Generate a exception for this error - allow caller to have consistent handling
            //
            if (errorMessage != null)
            {
                throw new Exception("DeleteQueue Error - " + errorMessage);
            }
        
            return "Success";
        }
    
        /// <summary>
        /// Send a SQS message
        /// </summary>
        /// <param name="queue"></param>
        /// <param name="message"></param>
        /// <returns></returns>
        public static string SendMessage(string queue, string message)
        {
            SendMessage             sendMessage;
            SendMessageResponse     response        = null;
            string                  errorMessage    = null;
        
            sendMessage             = new SendMessage();
            sendMessage.QueueName   = queue;
            sendMessage.MessageBody = message;
            
            //
            // Make request - retry if we get a 5xx error
            //
            try
            {
                response = _sqsClient.SendMessage(sendMessage);
            }
            catch (AmazonSQSException sqsException)
            {
                //
                // Oops - caught SQS error.  Process message...
                //
                errorMessage = ProcessSQSError(sqsException);
            }
            catch (Exception ex)
            {
                //
                // Oops - caught an error.
                //
                errorMessage = "Generic Error: " + ex.Message;
            }
            
            //
            // Generate a exception for this error - allow caller to have consistent handling
            //
            if (errorMessage != null)
            {
                throw new Exception("SendMessage Error - " + errorMessage);
            }
        
            return response.SendMessageResult.MessageId;
        }
    
        /// <summary>
        /// Try to receive a single message
        /// </summary>
        /// <param name="queue"></param>
        /// <returns></returns>
        public static Message ReceiveMessage(string queue)
        {
             Message[] msgs = RecieveMessage(queue, 1);
             if (msgs != null && msgs.Length > 0)
             {
                 return msgs[0];
             }

            return null;
        }
    
        /// <summary>
        /// 
        /// </summary>
        /// <param name="queue"></param>
        /// <param name="count"></param>
        /// <returns></returns>
        public static Message[] RecieveMessage(string queue, int count)
        {
            return RecieveMessage(queue, count, -1);
        }
    
        /// <summary>
        /// Try to receive several messages...
        /// </summary>
        /// <param name="queue"></param>
        /// <param name="count"></param>
        /// <param name="timeout"></param>
        /// <returns></returns>
        public static Message[] RecieveMessage(string queue, int count, int timeout)
        {            
            ReceiveMessageResponse  response        = null;
            string                  errorMessage    = null;
            Message[]               messages        = null;


            ReceiveMessage receiveMessage = new ReceiveMessage();
            receiveMessage.QueueName            = queue;
            receiveMessage.MaxNumberOfMessages  = Convert.ToDecimal(count);
            
            if (timeout != -1)
                receiveMessage.VisibilityTimeout = Convert.ToDecimal(timeout);
            
            //
            // Make request - retry if we get a 5xx error
            //
            try
            {
                response = _sqsClient.ReceiveMessage(receiveMessage);
            }
            catch (AmazonSQSException sqsException)
            {
                //
                // Oops - caught SQS error.  Process message...
                //
                errorMessage = ProcessSQSError(sqsException);
            }
            catch (Exception ex)
            {
                //
                // Oops - caught an error.
                //
                errorMessage = "Generic Error: " + ex.Message;
            }
            
            //
            // Generate a exception for this error - allow caller to have consistent handling
            //
            if (errorMessage != null)
                throw new Exception("ReceiveMessage Error - " + errorMessage);
        
            if (response.ReceiveMessageResult.Message.Count > 0)
            {
                messages = new Message[response.ReceiveMessageResult.Message.Count];
                response.ReceiveMessageResult.Message.CopyTo(messages);
            }

            return messages;
        }
    
        /// <summary>
        /// Delete a message...
        /// </summary>
        /// <param name="queue"></param>
        /// <param name="receipt"></param>
        /// <returns></returns>
        public static string DeleteMessage(string queue, string receipt)
        {
            DeleteMessageResponse   response        = null;
            string                  errorMessage    = null;

            DeleteMessage deleteMessage = new DeleteMessage();
            deleteMessage.QueueName     = queue;
            deleteMessage.ReceiptHandle = receipt;
        
            //
            // Make request - retry if we get a 5xx error
            //
            try
            {
                response = _sqsClient.DeleteMessage(deleteMessage);
            }
            catch (AmazonSQSException sqsException)
            {
                //
                // Oops - caught SQS error.  Process message...
                //
                errorMessage = ProcessSQSError(sqsException);
            }
            catch (Exception ex)
            {
                //
                // Oops - caught an error.
                //
                errorMessage = "Generic Error: " + ex.Message;
            }
            
            //
            // Generate a exception for this error - allow caller to have consistent handling
            //
            if (errorMessage != null)
                throw new Exception("DeleteMessage Error - " + errorMessage);
        
            return "Success";
        }
    
        /// <summary>
        /// Get Approximate Number of Messages in specified queue...
        /// </summary>
        /// <param name="queue"></param>
        /// <returns></returns>
        public static long ApproximateNumberOfMessages(string queue)
        {
            GetQueueAttributes          queueAttributes = new GetQueueAttributes();
            GetQueueAttributesResponse  response        = null;
            string                      errorMessage    = null;
            long                        result          = 0;
        
            queueAttributes.QueueName        = queue;
            queueAttributes.AttributeName.Add("ApproximateNumberOfMessages");
        
            //
            // Make request - retry if we get a 5xx error
            //
            try
            {
                response = _sqsClient.GetQueueAttributes(queueAttributes);
            }
            catch (AmazonSQSException sqsException)
            {
                //
                // Oops - caught SQS error.  Process message...
                //
                errorMessage = ProcessSQSError(sqsException);
            }
            catch (Exception ex)
            {
                //
                // Oops - caught an error.
                //
                errorMessage = "Generic Error: " + ex.Message;
            }
            
            //
            // Generate a exception for this error - allow caller to have consistent handling
            //
            if (errorMessage != null)
                throw new Exception("GetQueueAttributes Error - " + errorMessage);
            
            result = Convert.ToInt64(response.GetQueueAttributesResult.Attribute[0].Value);
            
            return result;
        }
    }
}
